package com.miplus.ccrm.core.service.crd;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.miplus.ccrm.common.*;
import com.miplus.ccrm.core.controller.vo.credit.*;
import com.miplus.ccrm.core.controller.vo.ficase.*;
import com.miplus.ccrm.core.mapper.*;
import com.miplus.ccrm.core.pojo.*;
import com.miplus.ccrm.core.security.JCommonData;
import com.miplus.ccrm.core.service.ExportService;
import com.miplus.ccrm.core.service.action.FiDelayService;
import com.miplus.ccrm.core.service.collect.*;
import com.miplus.ccrm.core.utils.EnumConfirmStatus;
import com.miplus.ccrm.core.utils.EnumFiCaseQueue;
import com.miplus.ccrm.core.utils.EnumFiCaseStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class FiCasesServiceCrdImpl implements FiCasesServiceCrd {
    @Resource
    private ConCustomertagMapper conCustomertagMapper;
    @Resource
    private ExportService exportService;
    @Resource
    private FiImportHistService fiImportHistService;
    @Resource
    private CreditAccountNoutbillMapper accountNoutbillMapper;
    @Resource
    private CreditAccountBalanceMapper creditAccountBalanceMapper;
    @Resource
    private CreditAccountMapper creditAccountMapper;
    @Resource
    private FiCreditcasesService caseService;
    @Resource
    private JCommonData jCommonData;
    @Resource
    private FiDelayService fiDelayService;
    @Resource
    private ConCustomerMapper customerMapper;

    private MPJLambdaWrapper getQueryWrapper(JSysUser user, boolean iscock, CrdCaseReqVo paras)
    {
        String noinctags="";
        String $usrid=user.getUsrid();
        String tags= JPubUtils.getInString(paras.getCusttaglist());
        String cardnos=JPubUtils.getInString(paras.getCardnolist());
        if(JPubUtils.IsNotEmpty(tags)){
            noinctags = JPubUtils.BoolToString(paras.getNoincludetags());
        }
        String noincaccts="";
        if(JPubUtils.IsNotEmpty(paras.getAcctstatus())){
            noincaccts = JPubUtils.BoolToString(paras.getNoincludeaccs());
        }
        //2024-07-24
        boolean viewAllCase= JUsrPerm.viewAllFiCase(user);
        //数据库尽量不要使用函数，否则慢,尤其TDSQL
        //.apply("fi_hasFiCaseView({0},t.creditcaseid,t.status,t.sendtodept,t.sendtousr)>0", $usrid)
        log.info("getQueryWrapper:viewAllCase={},iscock={}",viewAllCase,iscock);
        if(!iscock) {
            return new MPJLambdaWrapper<FiCreditcases>()
                    .innerJoin(ConCustomer.class, "cu", ConCustomer::getCustomernumber, FiCreditcases::getCustomernumber)
                    .leftJoin(CreditAccount.class, "cda", CreditAccount::getAcct, FiCreditcases::getCreditAcct)
                    .leftJoin(CreditAccountBalance.class, "cdb", CreditAccountBalance::getAcct, FiCreditcases::getCreditAcct)
                    .leftJoin(FiTask.class, "tk", FiTask::getTasknumber, FiCreditcases::getLastcctaskid)
                    .apply(!viewAllCase,JPubUtils.getPuvViewSql($usrid))
                    .eq(JPubUtils.IsNotEmpty(paras.getFicaseid()), FiCreditcases::getCreditcaseid, paras.getFicaseid())
                    .in(JPubUtils.IsNotEmpty(paras.getStatus()), FiCreditcases::getStatus, paras.getStatus())
                    .eq(JPubUtils.IsNotEmpty(paras.getCustnumber()), ConCustomer::getCustomernumber, paras.getCustnumber())
                    .eq(JPubUtils.IsNotEmpty(paras.getCusttype()), ConCustomer::getType, paras.getCusttype())
                    .likeRight(JPubUtils.IsNotEmpty(paras.getCustname()), ConCustomer::getCustname, paras.getCustname())
                    .eq(JPubUtils.IsNotEmpty(paras.getRisklevel()), ConCustomer::getRisklevel, paras.getRisklevel())
                    .eq(JPubUtils.IsNotEmpty(paras.getOpenacctcertno()), ConCustomer::getOpenacctcertno, paras.getOpenacctcertno())
                    .eq(JPubUtils.IsNotEmpty(paras.getAcctno()), FiCreditcases::getCreditAcct, paras.getAcctno())
                    .in(JPubUtils.IsNotEmpty(paras.getProdtype()), FiCreditcases::getProdtype, paras.getProdtype())
                    .eq(JPubUtils.IsNotEmpty(paras.getSendtodept()), FiCreditcases::getSendtodept, paras.getSendtodept())
                    .eq(JPubUtils.IsNotEmpty(paras.getSendtousr()), FiCreditcases::getSendtousr, paras.getSendtousr())
                    .eq(JPubUtils.IsNotEmpty(paras.getCcc()),FiCreditcases::getCcc,paras.getCcc())
                    .eq(JPubUtils.IsNotEmpty(paras.getDistbatchid()), FiCreditcases::getDistbatchid, paras.getDistbatchid())
                    .eq(JPubUtils.IsNotEmpty(paras.getAccttype()), CreditAccount::getAcctType, paras.getAccttype())
                    .eq(JPubUtils.IsNotEmpty(paras.getBatchid()), FiCreditcases::getBatchid, paras.getBatchid())
                    .ge(JPubUtils.IsNotEmpty(paras.getOdudPrin1()), CreditAccountBalance::getSettledBillAmt, paras.getOdudPrin1())
                    .le(JPubUtils.IsNotEmpty(paras.getOdudPrin2()), CreditAccountBalance::getSettledBillAmt, paras.getOdudPrin2())
                    .between(JPubUtils.IsNotEmpty(paras.getStartdt()), FiCreditcases::getCrdt, JPubUtils.StringToDate(paras.getStartdt()), JPubUtils.StringToDate(paras.getEnddt()))
                    .between(JPubUtils.IsNotEmpty(paras.getDiststartdt()), FiCreditcases::getDistdt, JPubUtils.StringToDate(paras.getDiststartdt()), JPubUtils.StringToDate(paras.getDistenddt()))
                    .between(JPubUtils.IsNotEmpty(paras.getAppointstartdt()), FiCreditcases::getAppointdt, JPubUtils.StringToDate(paras.getAppointstartdt()), JPubUtils.StringToDate(paras.getAppointenddt()))
                    .between(JPubUtils.IsNotEmpty(paras.getInstartdt()), FiCreditcases::getIndt, JPubUtils.StringToDate(paras.getInstartdt()), JPubUtils.StringToDate(paras.getInenddt()))
                    .between(JPubUtils.IsNotEmpty(paras.getRecystartdt()), FiCreditcases::getRecycledt, JPubUtils.StringToDate(paras.getRecystartdt()), JPubUtils.StringToDate(paras.getRecyenddt()))
                    .between(JPubUtils.IsNotEmpty(paras.getLastccstartdt()), FiCreditcases::getLastccdt, JPubUtils.StringToDate(paras.getLastccstartdt()), JPubUtils.StringToDate(paras.getLastccenddt()))
                    .eq(JPubUtils.IsNotEmpty(paras.getLastccresult()),FiTask::getResult,paras.getLastccresult())
                    .ge(JPubUtils.IsNotEmpty(paras.getMthsodue1()), CreditAccount::getMthsOdue, paras.getMthsodue1())
                    .le(JPubUtils.IsNotEmpty(paras.getMthsodue2()), CreditAccount::getMthsOdue, paras.getMthsodue2())
                    .ge(JPubUtils.IsNotEmpty(paras.getMthsday1()), CreditAccount::getMthsDay, paras.getMthsday1())
                    .le(JPubUtils.IsNotEmpty(paras.getMthsday2()), CreditAccount::getMthsDay, paras.getMthsday2())
                    .eq(JPubUtils.IsNotEmpty(paras.getIsamortcust()), CreditAccount::getIsAmortCust, paras.getIsamortcust())
                    .eq(JPubUtils.IsNotEmpty(paras.getBilldate()),CreditAccount::getBillDate,paras.getBilldate())
                    .eq(JPubUtils.IsNotEmpty(paras.getCurrency()),CreditAccount::getCurrency,paras.getCurrency())
                    .in(JPubUtils.IsNotEmpty(paras.getAcctFlevel()),CreditAccount::getAcctFlevel,paras.getAcctFlevel())
                    .apply(JPubUtils.IsEqual(paras.getIsfiamort(), "1"), "fc_hasFiAmort(t.creditcaseid)>0")
                    .apply(JPubUtils.IsEqual(paras.getIsfiamort(), "0"), "fc_hasFiAmort(t.creditcaseid)=0")
                    .in(JPubUtils.IsNotEmpty(paras.getOpenacctcertnolist()), ConCustomer::getOpenacctcertno, paras.getOpenacctcertnolist())
                    .in(JPubUtils.IsEqual(noincaccts, 0), CreditAccount::getAcctStatus, paras.getAcctstatus())
                    .notIn(JPubUtils.IsEqual(noincaccts, 1), CreditAccount::getAcctStatus, paras.getAcctstatus())
                    .exists(JPubUtils.IsNotEmpty(cardnos), String.format("select 1 from credit_card crd where crd.acct=t.credit_acct and crd.card_no in ('%s')", cardnos))
                    .exists(JPubUtils.IsNotEmpty(paras.getCardno()), String.format("select 1 from credit_card crd where crd.acct=t.credit_acct and crd.card_no='%s'", paras.getCardno()))
                    .apply(JPubUtils.IsEqual(noinctags, 0),String.format("cu.customernumber in (select tag.custid from con_customertag tag where tag.custid=t.customernumber and tag.id in ('%s'))", tags))
                    .apply(JPubUtils.IsEqual(noinctags, 1), String.format("cu.customernumber not in (select tag.custid from con_customertag tag where tag.custid=t.customernumber and tag.id in ('%s'))", tags))
                    .exists(JPubUtils.IsNotEmpty(paras.getCustphone()), String.format("select 1 from con_contact ct where ct.customernumber=t.customernumber and ct.phone='%s'",paras.getCustphone()))
                    .apply(JPubUtils.IsEqual(paras.getIscodebt(),"1"),"(select count(1) from fi_creditcases fi where fi.customernumber=t.customernumber and fi.ccc in('O','Q','S'))>1");
        }
        else{
            return new MPJLambdaWrapper<FiCreditcases>()
                    .innerJoin(ConCustomer.class, "cu", ConCustomer::getCustomernumber, FiCreditcases::getCustomernumber)
                    .leftJoin(CreditCockcollect.class, "cct", CreditCockcollect::getContractno, FiCreditcases::getCreditAcct)
                    .leftJoin(FiTask.class, "tk", FiTask::getTasknumber, FiCreditcases::getLastcctaskid)
                    .eq(FiCreditcases::getProdtype, "3")
                    .apply(!viewAllCase,JPubUtils.getPuvViewSql($usrid))
                    .eq(JPubUtils.IsNotEmpty(paras.getFicaseid()), FiCreditcases::getCreditcaseid, paras.getFicaseid())
                    .in(JPubUtils.IsNotEmpty(paras.getStatus()), FiCreditcases::getStatus, paras.getStatus())
                    .eq(JPubUtils.IsNotEmpty(paras.getCustnumber()), ConCustomer::getCustomernumber, paras.getCustnumber())
                    .eq(JPubUtils.IsNotEmpty(paras.getCusttype()), ConCustomer::getType, paras.getCusttype())
                    .likeRight(JPubUtils.IsNotEmpty(paras.getCustname()), ConCustomer::getCustname, paras.getCustname())
                    .eq(JPubUtils.IsNotEmpty(paras.getRisklevel()), ConCustomer::getRisklevel, paras.getRisklevel())
                    .eq(JPubUtils.IsNotEmpty(paras.getOpenacctcertno()), ConCustomer::getOpenacctcertno, paras.getOpenacctcertno())
                    .eq(JPubUtils.IsNotEmpty(paras.getAcctno()), FiCreditcases::getCreditAcct, paras.getAcctno())
                    .eq(JPubUtils.IsNotEmpty(paras.getSendtodept()), FiCreditcases::getSendtodept, paras.getSendtodept())
                    .eq(JPubUtils.IsNotEmpty(paras.getSendtousr()), FiCreditcases::getSendtousr, paras.getSendtousr())
                    .eq(JPubUtils.IsNotEmpty(paras.getCcc()),FiCreditcases::getCcc,paras.getCcc())
                    .eq(JPubUtils.IsNotEmpty(paras.getAccttype()), CreditCockcollect::getAcctType, paras.getAccttype())
                    .eq(JPubUtils.IsNotEmpty(paras.getDistbatchid()), FiCreditcases::getDistbatchid, paras.getDistbatchid())
                    .eq(JPubUtils.IsNotEmpty(paras.getBatchid()), FiCreditcases::getBatchid, paras.getBatchid())
                    .ge(JPubUtils.IsNotEmpty(paras.getOdudPrin1()), CreditCockcollect::getCrdprin, paras.getOdudPrin1())
                    .le(JPubUtils.IsNotEmpty(paras.getOdudPrin2()), CreditCockcollect::getCrdprin, paras.getOdudPrin2())
                    .between(JPubUtils.IsNotEmpty(paras.getStartdt()), FiCreditcases::getCrdt, JPubUtils.StringToDate(paras.getStartdt()), JPubUtils.StringToDate(paras.getEnddt()))
                    .between(JPubUtils.IsNotEmpty(paras.getDiststartdt()), FiCreditcases::getDistdt, JPubUtils.StringToDate(paras.getDiststartdt()), JPubUtils.StringToDate(paras.getDistenddt()))
                    .between(JPubUtils.IsNotEmpty(paras.getAppointstartdt()), FiCreditcases::getAppointdt, JPubUtils.StringToDate(paras.getAppointstartdt()), JPubUtils.StringToDate(paras.getAppointenddt()))
                    .between(JPubUtils.IsNotEmpty(paras.getInstartdt()), FiCreditcases::getIndt, JPubUtils.StringToDate(paras.getInstartdt()), JPubUtils.StringToDate(paras.getInenddt()))
                    .between(JPubUtils.IsNotEmpty(paras.getRecystartdt()), FiCreditcases::getRecycledt, JPubUtils.StringToDate(paras.getRecystartdt()), JPubUtils.StringToDate(paras.getRecyenddt()))
                    .between(JPubUtils.IsNotEmpty(paras.getLastccstartdt()), FiCreditcases::getLastccdt, JPubUtils.StringToDate(paras.getLastccstartdt()), JPubUtils.StringToDate(paras.getLastccenddt()))
                    .eq(JPubUtils.IsNotEmpty(paras.getLastccresult()),FiTask::getResult,paras.getLastccresult())
                    .apply(JPubUtils.IsEqual(paras.getIsfiamort(), "1"), "fc_hasFiAmort(t.creditcaseid)>0")
                    .apply(JPubUtils.IsEqual(paras.getIsfiamort(), "0"), "fc_hasFiAmort(t.creditcaseid)=0")
                    .in(JPubUtils.IsNotEmpty(paras.getOpenacctcertnolist()), ConCustomer::getOpenacctcertno, paras.getOpenacctcertnolist())
                    .apply(JPubUtils.IsEqual(noinctags, 0),String.format("cu.customernumber in (select tag.custid from con_customertag tag where tag.custid=t.customernumber and tag.id in ('%s'))", tags))
                    .apply(JPubUtils.IsEqual(noinctags, 1), String.format("cu.customernumber not in (select tag.custid from con_customertag tag where tag.custid=t.customernumber and tag.id in ('%s'))", tags))
                    .exists(JPubUtils.IsNotEmpty(paras.getCustphone()), String.format("select 1 from con_contact ct where ct.customernumber=t.customernumber and ct.phone='%s'",paras.getCustphone()))
                    .apply(JPubUtils.IsEqual(paras.getIscodebt(),"1"),"(select count(1) from fi_creditcases fi where fi.customernumber=t.customernumber and fi.ccc in('O','Q','S'))>1");
        }
    }

    @Override
    public IPage<CrdCaseResVo> crdCaseList(JSysUser user, CrdCaseReqVo paras)
    {
        String $usrid=user.getUsrid();
        String phnstar= JUsrPerm.getPermission(user,JUsrPerm.DISSTAR_PHN);
        String idstar= JUsrPerm.getPermission(user,JUsrPerm.DISSTAR_IDNO);
        String cardstar= JUsrPerm.getPermission(user,JUsrPerm.DISSTAR_CARD);
        boolean iscock=JPubUtils.hasValue(paras.getProdtype(),"3");
        MPJLambdaWrapper<FiCreditcases> quyWrapper=getQueryWrapper(user,iscock,paras);
        if(!iscock) {
            return caseService.selectJoinListPage(new Page<>(paras.getPageNum(), paras.getPageSize()),
                    CrdCaseResVo.class,
                    quyWrapper.selectAs(FiCreditcases::getCreditcaseid,CrdCaseResVo::getFicaseid)
                            .selectAs("fun_getnames('COLLECT.STATUS',t.status)", CrdCaseResVo::getStatusdsc)
                            .selectAs("fun_getnames('CUST.TYPE',cu.type)", CrdCaseResVo::getCusttypedsc)
                            .selectAs("(select g.grpname from sys_grp g where g.grpid=t.sendtodept)", CrdCaseResVo::getSendtodeptdsc)
                            .selectAs("fun_getnames('COLLECT.ODUE',cda.mths_odue)", CrdCaseResVo::getMthsOdue)
                            .selectAs("fun_getnames('COLLECT.QUEUE',t.ccc)", CrdCaseResVo::getCccdsc)
                            .selectAs("fun_getnames('BUSINESS.TYPE',t.prodtype)", CrdCaseResVo::getProdtypedsc)
                            .selectAs("cdb.age1_age6", CrdCaseResVo::getOdudPrin)
                            .selectAs("(case when t.ccc='S' then 1 else 0 end)", CrdCaseResVo::getIsstopcase)
                            .selectAs("tk.result", CrdCaseResVo::getLastccresult)
                            .selectAs("fun_getnames('CREDIT.ACCT.FLEVEL',cda.acct_flevel)",CrdCaseResVo::getAcctFlevel)
                            .selectAs("fun_getnames('CREDIT.ACCT.CY',cda.currency)",CrdCaseResVo::getCurrency)
                            .selectAs("fun_getnames('CREDIT.ACCT.STATUS',cda.acct_status)", CrdCaseResVo::getAcctStatusName)
                            .selectAs(String.format("fi_starSecu('%s','%s',cu.custphone,'%s')", $usrid, JUsrPerm.DISSTAR_PHN, phnstar), CrdCaseResVo::getCustphone)
                            .selectAs(String.format("fi_starSecu('%s','%s',cu.openacctcertno,'%s')", $usrid, JUsrPerm.DISSTAR_IDNO, idstar), CrdCaseResVo::getOpenacctcertno)
                            .selectAs(String.format("fi_starSecu('%s','%s',cda.crdt_card_repe_no,'%s')", $usrid, JUsrPerm.DISSTAR_CARD, cardstar), CrdCaseResVo::getCrdtCardRepeNo)
                            .select(FiCreditcases::getStatus, FiCreditcases::getCcc, FiCreditcases::getCreditAcct, FiCreditcases::getProdtype,
                                    FiCreditcases::getIndt, FiCreditcases::getDistdt, FiCreditcases::getSendtodept, FiCreditcases::getSendtousr, FiCreditcases::getRepay,
                                    FiCreditcases::getAppointdt, FiCreditcases::getLastccdt, FiCreditcases::getBindenddt, FiCreditcases::getStopautodistenddt,
                                    FiCreditcases::getDistbatchid,FiCreditcases::getDistusr,FiCreditcases::getAssigndt,FiCreditcases::getAssignusr,
                                    FiCreditcases::getRecycledt,FiCreditcases::getRecycleusr,FiCreditcases::getClosedt)
                            .select(ConCustomer::getCustomernumber, ConCustomer::getCustname, ConCustomer::getRisklevel, ConCustomer::getCorpname)
                            .select(CreditAccount::getBillDate,CreditAccount::getMthsDay)
                            .select(CreditAccountBalance::getLowestRepayBal, CreditAccountBalance::getAcctDebtAll, CreditAccountBalance::getSettledBillAmt)
            );
            // .orderByDesc(FiCreditcases::getIndt) 取消排序，否则TDSQL非常慢
        }
        else{
            return caseService.selectJoinListPage(new Page<>(paras.getPageNum(), paras.getPageSize()),
                    CrdCaseResVo.class,
                    quyWrapper.selectAs(FiCreditcases::getCreditcaseid,CrdCaseResVo::getFicaseid)
                            .selectAs("fun_getnames('COLLECT.STATUS',t.status)", CrdCaseResVo::getStatusdsc)
                            .selectAs("fun_getnames('CUST.TYPE',cu.type)", CrdCaseResVo::getCusttypedsc)
                            .selectAs("(select g.grpname from sys_grp g where g.grpid=t.sendtodept)", CrdCaseResVo::getSendtodeptdsc)
                            .selectAs("fun_getnames('COLLECT.QUEUE',t.ccc)", CrdCaseResVo::getCccdsc)
                            .selectAs("fun_getnames('BUSINESS.TYPE',t.prodtype)", CrdCaseResVo::getProdtypedsc)
                            .selectAs("cct.crdprin", CrdCaseResVo::getSettledBillAmt)
                            .selectAs("cct.debttotal", CrdCaseResVo::getOdudPrin)
                            .selectAs("(case when t.ccc='S' then 1 else 0 end)", CrdCaseResVo::getIsstopcase)
                            .selectAs("tk.result", CrdCaseResVo::getLastccresult)
                            .selectAs(String.format("fi_starSecu('%s','%s',cu.custphone,'%s')", $usrid, JUsrPerm.DISSTAR_PHN, phnstar), CrdCaseResVo::getCustphone)
                            .selectAs(String.format("fi_starSecu('%s','%s',cu.openacctcertno,'%s')", $usrid, JUsrPerm.DISSTAR_IDNO, idstar), CrdCaseResVo::getOpenacctcertno)
                            .select(FiCreditcases::getStatus, FiCreditcases::getCcc, FiCreditcases::getCreditAcct, FiCreditcases::getProdtype,
                                    FiCreditcases::getIndt, FiCreditcases::getDistdt, FiCreditcases::getSendtodept, FiCreditcases::getSendtousr, FiCreditcases::getRepay,
                                    FiCreditcases::getAppointdt, FiCreditcases::getLastccdt, FiCreditcases::getBindenddt, FiCreditcases::getStopautodistenddt,
                                    FiCreditcases::getDistbatchid,FiCreditcases::getDistusr,FiCreditcases::getAssigndt,FiCreditcases::getAssignusr,
                                    FiCreditcases::getRecycledt,FiCreditcases::getRecycleusr,FiCreditcases::getClosedt)
                            .select(ConCustomer::getCustomernumber, ConCustomer::getCustname, ConCustomer::getRisklevel, ConCustomer::getCorpname)
                            .orderByDesc(FiCreditcases::getIndt)
            );
        }
    }

    @Override
    public QuyAmtSumVo getQueryDebtSum(JSysUser user, CrdCaseReqVo paras)
    {
        boolean iscock=JPubUtils.hasValue(paras.getProdtype(),"3");
        MPJLambdaWrapper<FiCreditcases> quyWrapper=getQueryWrapper(user,iscock,paras);
        if(!iscock) {
            return caseService.selectJoinOne(QuyAmtSumVo.class,
                    quyWrapper.selectSum(CreditAccountBalance::getSettledBillAmt, QuyAmtSumVo::getAmtSum)
            );
        }
        else{
            return caseService.selectJoinOne(QuyAmtSumVo.class,
                    quyWrapper.selectSum(CreditCockcollect::getCrdprin, QuyAmtSumVo::getAmtSum)
            );
        }
    }

    @Override
    public CrdCaseInfoVo getCrdCaseInfo(JSysUser user, Integer ficaseid)
    {//单个查询也需要控制权限，防止页面输入creditcaseid直接打开
        // 2024-06-27 edit 当前账户余额 由总欠款字段改成：已出账单欠款+未出账单欠款
        String $usrid=user.getUsrid();
        String idstar= JUsrPerm.getPermission(user,JUsrPerm.DISSTAR_IDNO);
        String cardstar= JUsrPerm.getPermission(user,JUsrPerm.DISSTAR_CARD);
        //2024-07-24
        boolean viewAllCase=JUsrPerm.viewAllFiCase(user);
        CrdCaseInfoVo resVo=caseService.selectJoinOne(
                CrdCaseInfoVo .class,
                new MPJLambdaWrapper<FiCreditcases>()
                        .selectAs(FiCreditcases::getCreditcaseid,CrdCaseInfoVo::getFicaseid)
                        .selectAs("fun_getnames('COLLECT.STATUS',t.status)",CrdCaseInfoVo::getStatusdsc)
                        .selectAs("fun_getnames('CUST.TYPE',cu.type)",CrdCaseInfoVo::getCusttypedsc)
                        .selectAs("(select g.grpname from sys_grp g where g.grpid=t.sendtodept)",CrdCaseInfoVo::getSendtodeptdsc)
                        .selectAs("fun_getnames('COLLECT.ODUE',cda.mths_odue)",CrdCaseInfoVo::getMthsOdue)
                        .selectAs("fun_getnames('COLLECT.QUEUE',t.ccc)", CrdCaseResVo::getCccdsc)
                        .selectAs("fun_getnames('BUSINESS.TYPE',t.prodtype)",CrdCaseInfoVo::getProdtypedsc)
                        .selectAs("fun_getnames('MARRIAGE.STATUS',cu.marrgstatus)",CrdCaseInfoVo::getMarrgstatus)
                        .selectAs("fun_getnames('CON.SEX',cu.gender)",CrdCaseInfoVo::getGender)
                        .selectAs("fun_getnames('CON.EDU',cu.heightedudegr)",CrdCaseInfoVo::getHeightedudegr)
                        .selectAs("fun_getnames('CON.PSTN',cu.pstn)",CrdCaseInfoVo::getPstn)
                        .selectAs("fun_getnames('CON.CERTTYPE',cu.openacctcerttype)", CrdCaseInfoVo::getOpenacctcerttype)
                        .selectAs("fun_getnames('CREDIT.ACCT.STATUS',cda.acct_status)",CrdCaseInfoVo::getAcctStatus)
                        .selectAs("fun_getnames('BUSINESS.TYPE',t.prodtype)",CrdCaseInfoVo::getProdtypedsc)
                        .selectAs("cdb.age1_age6",CrdCaseInfoVo::getOdudPrin)
                        .selectAs("fi_hasHoldCard(t.credit_acct)",CrdCaseInfoVo::getIsholdCard)
                        .selectAs("(case when t.ccc='S' then 1 else 0 end)", CrdCaseInfoVo::getIsstopcase)
                        .selectAs("cdb.mddt", CrdCaseInfoVo::getAccBalLastUpTime)
                        .selectAs("fun_getnames('CREDIT.ACCT.CY',cda.currency)",CrdCaseInfoVo::getCurrency)
                        .selectAs("fun_getnames('CREDIT.ACCT.FLEVEL',cda.acct_flevel)",CrdCaseInfoVo::getAcctFlevel)
                        .selectAs("(case when cdb.settled_bill_amt is null then 0.0 else cdb.settled_bill_amt end+case when cdb.unsettled_bill_amt is null then 0.0 else cdb.unsettled_bill_amt end)",CrdCaseInfoVo::getAcctDebtAmt)
                        .selectAs(String.format("fi_starSecu('%s','%s',cu.openacctcertno,'%s')",$usrid,JUsrPerm.DISSTAR_IDNO,idstar),CrdCaseInfoVo::getOpenacctcertno)
                        .selectAs(String.format("fi_starSecu('%s','%s',cu.debitcardno,'%s')",$usrid,JUsrPerm.DISSTAR_CARD,cardstar),CrdCaseInfoVo::getDebitcardno)
                        .selectAs(String.format("fi_starSecu('%s','%s',cda.debit_card_num,'%s')",$usrid,JUsrPerm.DISSTAR_CARD,cardstar),CrdCaseInfoVo::getDebitCardNum)
                        .selectAs("fc_hasFiAmort(t.creditcaseid)", CrdCaseInfoVo::getFiamortcount)
                        .apply(!viewAllCase,JPubUtils.getPuvViewSql($usrid))
                        .leftJoin(ConCustomer.class,"cu",ConCustomer::getCustomernumber,FiCreditcases::getCustomernumber)
                        .leftJoin(CreditAccount.class,"cda",CreditAccount::getAcct,FiCreditcases::getCreditAcct)
                        .leftJoin(CreditAccountBalance.class,"cdb",CreditAccountBalance::getAcct,FiCreditcases::getCreditAcct)
                        .select(FiCreditcases::getStatus,FiCreditcases::getCreditAcct,FiCreditcases::getCcc,FiCreditcases::getCreditAcct,
                                FiCreditcases::getProdtype,FiCreditcases::getIndt,FiCreditcases::getDistdt,FiCreditcases::getSendtodept,FiCreditcases::getSendtousr,FiCreditcases::getRepay,
                                FiCreditcases::getAppointdt,FiCreditcases::getLastccdt,FiCreditcases::getBindenddt,FiCreditcases::getStopautodistenddt)
                        .select(ConCustomer::getCustomernumber,ConCustomer::getCustname,ConCustomer::getRisklevel,ConCustomer::getDepartment,ConCustomer::getCorpname,
                                ConCustomer::getAnnualincome,ConCustomer::getCustacctorgno,ConCustomer::getCustenname,ConCustomer::getCustemail,ConCustomer::getIsbankemply, ConCustomer::getBirthday)
                        .select(CreditAccount::getBillDate,CreditAccount::getRepayDate,CreditAccount::getMthsDay,
                                CreditAccount::getHRepayRecord24m,CreditAccount::getIsBindAutoRepay,CreditAccount::getIsAmortCust,
                                CreditAccount::getCrdtLimit,CreditAccount::getTempLimit)
                        .select(CreditAccountBalance::getSettledBillAmt,CreditAccountBalance::getSettledBillPrin,
                                CreditAccountBalance::getLowestRepayBal,CreditAccountBalance::getAcctDebtAll)
                        .eq("creditcaseid",ficaseid)
        );
        List<ConCustomertag> custtags=conCustomertagMapper.selectJoinList(
                ConCustomertag.class,
                new MPJLambdaWrapper<ConCustomertag>()
                        .leftJoin(FiCreditcases.class,"fc",FiCreditcases::getCustomernumber,ConCustomertag::getCustid)
                        .selectAll(ConCustomertag.class)
                        .eq("fc.creditcaseid",ficaseid)
        );
        if(custtags!=null&&custtags.size()>0){
            List<String> tags=custtags.stream().map(ConCustomertag::getId).collect(Collectors.toList());
            resVo.setCusttags(tags);
        }

        return resVo;
    }

    private int bindFiCastList(List<Integer> caseList,JSysUser user,CrdCaseReqVo paras)
    {//2024-07-28
        //List<Integer> arr=new LinkedList<>();
        boolean iscock=JPubUtils.hasValue(paras.getProdtype(),"3");
        log.info("bindFiCastList:distMaxCount={},iscock={}",JPubUtils.distMaxCount,iscock);
        MPJLambdaWrapper<FiCreditcases> quyWrapper=getQueryWrapper(user,iscock,paras);
        IPage<CrdCaseResVo> pages=caseService.selectJoinListPage(new Page<>(1, JPubUtils.distMaxCount),
                CrdCaseResVo.class,
                quyWrapper.select(FiCreditcases::getCreditcaseid)
        );
        log.info("bindFiCastList:total={},page={},size={}",pages.getTotal(),pages.getPages(),pages.getSize());
        pages.convert(u->{
            caseList.add(u.getFicaseid());
            return u;
        });
        //Collections.copy(caseList,arr);
        return caseList.size();
    }

    //信用卡案件分案
    @Override
    public List<DistResVo> crdCaseDistribute(JSysUser user, DistReqVo paras, CrdCaseReqVo distParas) {
        List<Integer> dataCaseList=null;
        if (paras.getIspredist() == JPubUtils.PRE_OPERATE) {
            dataCaseList = paras.getFicaseList();
            if (distParas != null) {//使用查询条件取分配数据(一键分案)
                bindFiCastList(dataCaseList, user, distParas);

                log.info("crdCaseDistribute:Count={}", dataCaseList.size());
                if(dataCaseList.size()==0){
                    throw new ServiceException(EnumRCode.NoFindPreDist.value, EnumRCode.NoFindPreDist.name);
                }
            }
        }

        return caseService.fiCaseDistribute(user,paras,dataCaseList);
    }

    @Override
    public List<DistResVo> crdCaseAssign(JSysUser user, AssReqVo paras, CrdCaseReqVo distParas)
    {
        List<Integer> dataCaseList=null;
        if (paras.getIspreass() == JPubUtils.PRE_OPERATE) {
            dataCaseList = paras.getFicaseList();
            if (distParas != null) {//使用查询条件取分配数据(一键分案)
                bindFiCastList(dataCaseList, user, distParas);

                log.info("crdCaseAssign:Count={}", dataCaseList.size());
                if(dataCaseList.size()==0){
                    throw new ServiceException(EnumRCode.NoFindPreDist.value, EnumRCode.NoFindPreDist.name);
                }
            }
        }

        return caseService.fiCaseAssign(user,paras,dataCaseList);
    }

    @Override
    public CmdResVo crdCaseRecycle(JSysUser user, RecyReqVo paras, CrdCaseReqVo dataParas)
    {
        boolean oneRecycle=false;
        List<Integer> recylistID=paras.getFicaseList();
        if((paras.getRecymode()==JPubUtils.RECY_MODE_TOP)&&(dataParas!=null)){
            if(jCommonData.IsRecycleProcess()){
                log.info("fiCaseRecycle.IsRecycleProcess...");
                return new CmdResVo(0);
            }
            oneRecycle=true;
            //放到这里为了解决下面查询数据可能时间比较长时，客户端请求返回0，否则返回-1就结束了，2024-09-27
            jCommonData.SetRecycleProcess(0);
            recylistID=new LinkedList<>();
            bindFiCastList(recylistID,user,dataParas);
            //recylist=caseService.getRecyCaseList(recylistID);
            log.info("fiCaseRecycle.recylist={},mode={} oneRecycle",recylistID.size(),paras.getRecymode());
        }
        else{
            //recylist=caseService.getRecyCaseList(recylistID);
            log.info("fiCaseRecycle.recylist={},mode={}",recylistID.size(),paras.getRecymode());
        }

        return caseService.fiCaseRecycle(user,paras,recylistID,oneRecycle);
    }

    @Override
    public CmdResVo getOneRecyCount(JSysUser user,CrdCaseReqVo dataParas)
    {//2024-09-27 为了客户端异常处理
        int cnt=0;
        if(dataParas!=null){
            List<Integer> recylistID = new LinkedList<>();
            cnt = bindFiCastList(recylistID, user, dataParas);
            log.info("getOneRecyCount={}", cnt);
        }
        return new CmdResVo(cnt);
    }

    @Override
    public CmdResVo crdCaseTranDist(JSysUser user, TranDistReqVo paras, CrdCaseReqVo distParas)
    {
        if(!JPubUtils.IsEqual(paras.getIsquydist(),"1")&&JPubUtils.IsEmpty(paras.getFicaseList())){
            throw new ServiceException(EnumRCode.ArgErr.value, EnumRCode.ArgErr.name);
        }

        List<Integer> distCaseList = paras.getFicaseList();
        if (JPubUtils.IsEqual(paras.getIsquydist(),"1")) {//使用查询条件取分配数据
            bindFiCastList(distCaseList, user, distParas);
        }

        return caseService.fiCaseTranDist(user,paras,distCaseList);
    }

    @Override
    public CmdResVo crdCaseSaveAs(JSysUser user, CrdCaseReqVo paras, HttpServletResponse response) {
        String $usrid = user.getUsrid();
        int pagesize = paras.getPageSize();
        if (pagesize > JPubUtils.exportMaxCount) {
            paras.setPageSize(JPubUtils.exportMaxCount);
        }
        log.info("crdCaseSaveAs:pagesize={}",pagesize);

        IPage<CrdCaseResVo> pages=crdCaseList(user, paras);
        ArrayList arr=new ArrayList();

        String exptempid=JPubUtils.getExpTempID(paras.getExpfilename(),"案件表");
        String filename=JPubUtils.getExpFileName(
                paras.getExpfilename(),exptempid
        );
        pages.convert(u->{
            HashMap map=JPubUtils.toExportMap(u);
            if(map!=null) arr.add(map);
            return u;
        });
        CmdResVo resVo=exportService.ToExcel(
                response,
                arr,
                paras.getExpidlist(),
                paras.getExpnamelist(),
                filename,
                $usrid
        );

        int okcount=resVo.getCount();
        if(okcount>0){
            fiImportHistService.AddExportHist(
                    resVo.getKeyId(),
                    $usrid,
                    exptempid,
                    filename,
                    okcount
            );
        }
        arr.clear();

        return resVo;
    }

    @Override
    public CrdCmdResVo refreshBalance(JSysUser user,CrdRefreshBalVo paras)
    {
        CrdCmdResVo resVo=new CrdCmdResVo();
        if(paras.getType()==2){
            if(!JUsrPerm.hasPermission(user,"division")){ //待分案菜单
                throw new ServiceException(EnumRCode.Forbidden.value, EnumRCode.Forbidden.name);
            }
            List<LinkedHashMap> casesList=caseService.selectJoinList(LinkedHashMap.class,
                    new MPJLambdaWrapper<FiCreditcases>()
                            .innerJoin(CreditAccount.class,"ct",CreditAccount::getAcct,FiCreditcases::getCreditAcct)
                            .select(CreditAccount::getCustNo,CreditAccount::getCrdtCardRepeNo,CreditAccount::getAcct)
                            .select(FiCreditcases::getCreditcaseid,FiCreditcases::getProdtype)
                            .in(FiCreditcases::getProdtype,"1","2")
                            .eq("ccc", EnumFiCaseQueue.O.name)
            );
            log.info("refreshBalance:count={}",casesList.size());
            if(casesList.size()>=100){
                resVo.setTotal(casesList.size());
                resVo.setRespCode("0");
                resVo.setRespCodeDesc("数据量太多，禁止全量手动刷新!");
                return resVo;
            }
            int okcount=0,rpccount=0;
            for(LinkedHashMap cases : casesList){
                CrdCmdResVo cmdResVo= CrdCommand.cardAcctBusiness(cases.get("cust_no").toString(),
                        cases.get("crdt_card_repe_no").toString(),
                        paras.getCurrency()
                );
                if(JPubUtils.IsEqual(cmdResVo.getRespCode(),"0")){
                    okcount++;
                    Integer ficaseid=JPubUtils.StringToInt(cases.get("creditcaseid").toString());
                    DoUpdateCase(user.getUsrid(),ficaseid,cases.get("acct").toString(),cmdResVo);
                    if(cmdResVo.getIsRpc()==1){
                        rpccount++;
                    }
                }
            }
            resVo.setRpccount(rpccount);
            resVo.setTotal(casesList.size());
            resVo.setOkcount(okcount);
            resVo.setRespCode("0");
            resVo.setRespCodeDesc("success");
        }else if(JPubUtils.IsEmpty(paras.getFicaseid())){
            throw new ServiceException(EnumRCode.ArgErr.value, EnumRCode.ArgErr.name);
        }
        else {
            FiCreditcases fi = caseService.getBaseMapper().selectById(paras.getFicaseid());
            //出催队列不在允许刷新余额,出催也可以刷余额，2024-06-25
            //if (JPubUtils.IsEqual(fi.getCcc(), EnumFiCaseQueue.R.name)) {
            //    resVo.setTotal(0);
            //    resVo.setIsRpc(1);
            //     resVo.setRespCode("0");
            //    resVo.setRespCodeDesc("案件已出催!");
            //} else{
            CreditAccount account=creditAccountMapper.selectOne(
                    new QueryWrapper<CreditAccount>().eq("acct",fi.getCreditAcct()));
            String cardno=account.getCrdtCardRepeNo();
            resVo = CrdCommand.cardAcctBusiness(fi.getCustomernumber(),
                    cardno, paras.getCurrency()
            );
            if(JPubUtils.IsEqual(resVo.getRespCode(), "0")) {
                DoUpdateCase(user.getUsrid(), paras.getFicaseid(), fi.getCreditAcct(), resVo);

                if(resVo.getMthsOdue()<0){//2024-06-06
                    resVo.setMthsOdue(account.getMthsOdue());
                }
            }
            resVo.setTotal(1);
            //}
        }
        return resVo;
    }

    @Override
    public CrdCmdResVo refreshNoOutBill(JSysUser user,CrdRefNOutBillVo paras)
    {
        FiCreditcases fi=caseService.getBaseMapper().selectById(paras.getFicaseid());
        CreditAccount account=creditAccountMapper.selectOne(
                new QueryWrapper<CreditAccount>().eq("acct",fi.getCreditAcct()));
        String cardno=account.getCrdtCardRepeNo();
        String acctno=fi.getCreditAcct();
        log.info("refreshNoOutBill:{}->{}",acctno,cardno);
        CrdCmdResVo resVo=null;
        if(JPubUtils.IsEqual(fi.getProdtype(),"1")){//银数
            resVo=CrdCommand.notOutBillDetailYs(cardno,null);
        }
        else{
            resVo=CrdCommand.notOutBillDetailTl(cardno);
        }
        accountNoutbillMapper.delete(new QueryWrapper<CreditAccountNoutbill>()
                .eq("acct", acctno)
        );
        if (JPubUtils.IsNotEmpty(resVo.getBillTailList())) {
            resVo.setTotal(resVo.getBillTailList().size());
            for(CrdBillTailResVo tailResVo : resVo.getBillTailList()){
                CreditAccountNoutbill def=new CreditAccountNoutbill();
                BeanUtils.copyProperties(tailResVo,def);
                def.setCardNbr(tailResVo.getCardNo());
                def.setDataDt(new Date());
                def.setAcct(acctno);
                def.setIsnotbill(1);
                log.info("refreshNoOutBill.save:{}",def);
                accountNoutbillMapper.insert(def);
            }
        } else resVo.setTotal(0);

        if(JPubUtils.IsEqual(fi.getProdtype(),"2")) {//通联
            refreshNotBill(acctno,cardno);
        }

        return resVo;
    }

    @Override
    public void refreshNotBill(String acctno,String cardno)
    {
        log.info("refreshNotBill:{}->{}",acctno,cardno);
        CrdCmdResVo resVo=CrdCommand.notBillDetailTl(cardno);

        if (JPubUtils.IsNotEmpty(resVo.getBillTailList())) {
            resVo.setTotal(resVo.getBillTailList().size());
            for(CrdBillTailResVo tailResVo : resVo.getBillTailList()){
                CreditAccountNoutbill def=new CreditAccountNoutbill();
                BeanUtils.copyProperties(tailResVo,def);
                def.setCardNbr(tailResVo.getCardNo());
                def.setDataDt(new Date());
                def.setAcct(acctno);
                def.setIsnotbill(0);
                log.info("refreshNotBill.save:{}",def);
                accountNoutbillMapper.insert(def);
            }
        }
    }

    private void DoUpdateCase(String $usrid,Integer ficaseid,String acctno,CrdCmdResVo cmdResVo)
    {//案件出催
        LinkedHashMap p=new LinkedHashMap();
        if(JPubUtils.IsNotEmpty(cmdResVo.getMthsOdue())) {
            CreditAccountBalance balance = new CreditAccountBalance();
            balance.setSettledBillAmt(cmdResVo.getSettledBillAmt());
            p.put("odud_prin",cmdResVo.getSettledBillAmt());
            balance.setLowestRepayBal(cmdResVo.getLowestRepayBal());
            if(cmdResVo.getUnsettledBillAmt()!=null){
                balance.setUnsettledBillAmt(cmdResVo.getUnsettledBillAmt());
            }
            if(cmdResVo.getInterestFee()!=null){
                balance.setInterestFee(cmdResVo.getInterestFee());
                p.put("interest_fee",cmdResVo.getInterestFee());
            }
            if(cmdResVo.getPenchgAcc()!=null){
                balance.setPenchgAcc(cmdResVo.getPenchgAcc());
                p.put("penchg_acc",cmdResVo.getPenchgAcc());
            }
            if(cmdResVo.getOthExpense()!=null){
                balance.setOthExpense(cmdResVo.getOthExpense());
                p.put("oth_expense",cmdResVo.getOthExpense());
            }
            if(cmdResVo.getIntChgd()!=null){
                balance.setIntChgd(cmdResVo.getIntChgd());
                p.put("penchg_acc",cmdResVo.getIntChgd());
            }
            if(cmdResVo.getPaymtClrd()!=null){
                balance.setPaymtClrd(cmdResVo.getPaymtClrd());
            }
            if(cmdResVo.getAge1Age6()!=null){
                balance.setAge1Age6(cmdResVo.getAge1Age6());
            }
            if(cmdResVo.getAcctDebtAll()!=null){
                balance.setAcctDebtAll(cmdResVo.getAcctDebtAll());
            }
            balance.setMddt(new Date());
            creditAccountBalanceMapper.update(balance,
                    new QueryWrapper<CreditAccountBalance>().eq("acct", acctno));

            CreditAccount account=new CreditAccount();
            if(cmdResVo.getMthsOdue()>=0) {
                //银数逾期期数不用減1， 通联逾期期数判断接口返回为9的时候，源期数保持不变，当为逾期期数小于9的时候使用接口参数減1
                //通联逾期期数=9,返回-1
                account.setMthsOdue(cmdResVo.getMthsOdue());
            }
            else{
                log.info("DoUpdateCase({}).MthsOdue={}",ficaseid,cmdResVo.getMthsOdue());
            }
            p.put("mths_odue",cmdResVo.getMthsOdue());
            account.setMddt(new Date());
            creditAccountMapper.update(account,
                    new QueryWrapper<CreditAccount>().eq("acct",acctno));
        }
        if(cmdResVo.getIsRpc()==1){//出催
            //V2.0不在使用，案件生成时就写入了，每天跑批时更新
            //LinkedHashMap p=caseService.getFiCaseAcctBal(ficaseid);
            FiCreditcases fi=new FiCreditcases();
            fi.setCreditcaseid(ficaseid);
            caseService.BuildFiCaseAmt(fi,p);

            //2024-08-02 一起放在BuildFiCaseAmt处理了
            //BigDecimal payamt=getPayAmount(ficaseid);
            //fi.setRepay(payamt);

            fi.setStatus(EnumFiCaseStatus.Finish.value);
            fi.setStatusdt(new Date());
            fi.setCcc(EnumFiCaseQueue.R.name);
            fi.setCloseusr($usrid);
            fi.setClosedt(new Date());
            fi.setMdusr($usrid);
            fi.setMddt(new Date());
            fi.setAppointdt(null);

            caseService.updateById(fi);
            caseService.updateToHistByID(ficaseid);

            List<Integer> list=new LinkedList<>();
            list.add(ficaseid);
            fiDelayService.doCancel($usrid,list, EnumConfirmStatus.Pass.value);
        }
    }

    @Override
    public CrdCmdResVo getCrdAcctBalance(Integer ficaseid, String cardno){
        FiCreditcases fi=caseService.getById(ficaseid);
        String paycardno=cardno;
        if(JPubUtils.IsEmpty(cardno)||cardno.indexOf("*")>=0){
            ConCustomer cu=customerMapper.selectById(fi.getCustomernumber());
            paycardno=cu.getDebitcardno();
        }
        return CrdCommand.crdAcctBalance(paycardno);
    }
}
